Passed
Push — master ( 1955b9...c5754d )
by Darío
06:42
created

popper-1.12.9.js ➔ ... ➔ update$$1   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 3
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 2
dl 3
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
/**!
2
 * @fileOverview Kickass library to create and place poppers near their reference elements.
3
 * @version 1.12.9
4
 * @license
5
 * Copyright (c) 2016 Federico Zivolo and contributors
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in all
15
 * copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
 */
25 View Code Duplication
(function (global, factory) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
26
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
27
	typeof define === 'function' && define.amd ? define(factory) :
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
28
	(global.Popper = factory());
29
}(this, (function () { 'use strict';
30
31
var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
32
var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
33
var timeoutDuration = 0;
34
for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
35
  if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
36
    timeoutDuration = 1;
37
    break;
38
  }
39
}
40
41
function microtaskDebounce(fn) {
42
  var called = false;
43
  return function () {
44
    if (called) {
45
      return;
46
    }
47
    called = true;
48
    window.Promise.resolve().then(function () {
49
      called = false;
50
      fn();
51
    });
52
  };
53
}
54
55
function taskDebounce(fn) {
56
  var scheduled = false;
57
  return function () {
58
    if (!scheduled) {
59
      scheduled = true;
60
      setTimeout(function () {
61
        scheduled = false;
62
        fn();
63
      }, timeoutDuration);
64
    }
65
  };
66
}
67
68
var supportsMicroTasks = isBrowser && window.Promise;
69
70
/**
71
* Create a debounced version of a method, that's asynchronously deferred
72
* but called in the minimum time possible.
73
*
74
* @method
75
* @memberof Popper.Utils
76
* @argument {Function} fn
77
* @returns {Function}
78
*/
79
var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;
80
81
/**
82
 * Check if the given variable is a function
83
 * @method
84
 * @memberof Popper.Utils
85
 * @argument {Any} functionToCheck - variable to check
86
 * @returns {Boolean} answer to: is a function?
87
 */
88
function isFunction(functionToCheck) {
89
  var getType = {};
90
  return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
91
}
92
93
/**
94
 * Get CSS computed property of the given element
95
 * @method
96
 * @memberof Popper.Utils
97
 * @argument {Eement} element
98
 * @argument {String} property
99
 */
100
function getStyleComputedProperty(element, property) {
101
  if (element.nodeType !== 1) {
102
    return [];
103
  }
104
  // NOTE: 1 DOM access here
105
  var css = getComputedStyle(element, null);
106
  return property ? css[property] : css;
107
}
108
109
/**
110
 * Returns the parentNode or the host of the element
111
 * @method
112
 * @memberof Popper.Utils
113
 * @argument {Element} element
114
 * @returns {Element} parent
115
 */
116
function getParentNode(element) {
117
  if (element.nodeName === 'HTML') {
118
    return element;
119
  }
120
  return element.parentNode || element.host;
121
}
122
123
/**
124
 * Returns the scrolling parent of the given element
125
 * @method
126
 * @memberof Popper.Utils
127
 * @argument {Element} element
128
 * @returns {Element} scroll parent
129
 */
130
function getScrollParent(element) {
131
  // Return body, `getScroll` will take care to get the correct `scrollTop` from it
132
  if (!element) {
133
    return document.body;
134
  }
135
136
  switch (element.nodeName) {
137
    case 'HTML':
138
    case 'BODY':
139
      return element.ownerDocument.body;
140
    case '#document':
141
      return element.body;
142
  }
143
144
  // Firefox want us to check `-x` and `-y` variations as well
145
146
  var _getStyleComputedProp = getStyleComputedProperty(element),
147
      overflow = _getStyleComputedProp.overflow,
148
      overflowX = _getStyleComputedProp.overflowX,
149
      overflowY = _getStyleComputedProp.overflowY;
150
151
  if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) {
152
    return element;
153
  }
154
155
  return getScrollParent(getParentNode(element));
156
}
157
158
/**
159
 * Returns the offset parent of the given element
160
 * @method
161
 * @memberof Popper.Utils
162
 * @argument {Element} element
163
 * @returns {Element} offset parent
164
 */
165
function getOffsetParent(element) {
166
  // NOTE: 1 DOM access here
167
  var offsetParent = element && element.offsetParent;
168
  var nodeName = offsetParent && offsetParent.nodeName;
169
170
  if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
171
    if (element) {
172
      return element.ownerDocument.documentElement;
173
    }
174
175
    return document.documentElement;
176
  }
177
178
  // .offsetParent will return the closest TD or TABLE in case
179
  // no offsetParent is present, I hate this job...
180
  if (['TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
181
    return getOffsetParent(offsetParent);
182
  }
183
184
  return offsetParent;
185
}
186
187
function isOffsetContainer(element) {
188
  var nodeName = element.nodeName;
189
190
  if (nodeName === 'BODY') {
191
    return false;
192
  }
193
  return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;
194
}
195
196
/**
197
 * Finds the root node (document, shadowDOM root) of the given element
198
 * @method
199
 * @memberof Popper.Utils
200
 * @argument {Element} node
201
 * @returns {Element} root node
202
 */
203
function getRoot(node) {
204
  if (node.parentNode !== null) {
205
    return getRoot(node.parentNode);
206
  }
207
208
  return node;
209
}
210
211
/**
212
 * Finds the offset parent common to the two provided nodes
213
 * @method
214
 * @memberof Popper.Utils
215
 * @argument {Element} element1
216
 * @argument {Element} element2
217
 * @returns {Element} common offset parent
218
 */
219
function findCommonOffsetParent(element1, element2) {
220
  // This check is needed to avoid errors in case one of the elements isn't defined for any reason
221
  if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
222
    return document.documentElement;
223
  }
224
225
  // Here we make sure to give as "start" the element that comes first in the DOM
226
  var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;
0 ignored issues
show
Bug introduced by
The variable Node seems to be never declared. If this is a global, consider adding a /** global: Node */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
227
  var start = order ? element1 : element2;
228
  var end = order ? element2 : element1;
229
230
  // Get common ancestor container
231
  var range = document.createRange();
232
  range.setStart(start, 0);
233
  range.setEnd(end, 0);
234
  var commonAncestorContainer = range.commonAncestorContainer;
235
236
  // Both nodes are inside #document
237
238
  if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {
239
    if (isOffsetContainer(commonAncestorContainer)) {
240
      return commonAncestorContainer;
241
    }
242
243
    return getOffsetParent(commonAncestorContainer);
244
  }
245
246
  // one of the nodes is inside shadowDOM, find which one
247
  var element1root = getRoot(element1);
248
  if (element1root.host) {
249
    return findCommonOffsetParent(element1root.host, element2);
250
  } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
251
    return findCommonOffsetParent(element1, getRoot(element2).host);
252
  }
253
}
254
255
/**
256
 * Gets the scroll value of the given element in the given side (top and left)
257
 * @method
258
 * @memberof Popper.Utils
259
 * @argument {Element} element
260
 * @argument {String} side `top` or `left`
261
 * @returns {number} amount of scrolled pixels
262
 */
263
function getScroll(element) {
264
  var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';
265
266
  var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
267
  var nodeName = element.nodeName;
268
269
  if (nodeName === 'BODY' || nodeName === 'HTML') {
270
    var html = element.ownerDocument.documentElement;
271
    var scrollingElement = element.ownerDocument.scrollingElement || html;
272
    return scrollingElement[upperSide];
273
  }
274
275
  return element[upperSide];
276
}
277
278
/*
279
 * Sum or subtract the element scroll values (left and top) from a given rect object
280
 * @method
281
 * @memberof Popper.Utils
282
 * @param {Object} rect - Rect object you want to change
283
 * @param {HTMLElement} element - The element from the function reads the scroll values
284
 * @param {Boolean} subtract - set to true if you want to subtract the scroll values
285
 * @return {Object} rect - The modifier rect object
286
 */
287
function includeScroll(rect, element) {
288
  var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
289
290
  var scrollTop = getScroll(element, 'top');
291
  var scrollLeft = getScroll(element, 'left');
292
  var modifier = subtract ? -1 : 1;
293
  rect.top += scrollTop * modifier;
294
  rect.bottom += scrollTop * modifier;
295
  rect.left += scrollLeft * modifier;
296
  rect.right += scrollLeft * modifier;
297
  return rect;
298
}
299
300
/*
301
 * Helper to detect borders of a given element
302
 * @method
303
 * @memberof Popper.Utils
304
 * @param {CSSStyleDeclaration} styles
305
 * Result of `getStyleComputedProperty` on the given element
306
 * @param {String} axis - `x` or `y`
307
 * @return {number} borders - The borders size of the given axis
308
 */
309
310
function getBordersSize(styles, axis) {
311
  var sideA = axis === 'x' ? 'Left' : 'Top';
312
  var sideB = sideA === 'Left' ? 'Right' : 'Bottom';
313
314
  return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10);
315
}
316
317
/**
318
 * Tells if you are running Internet Explorer 10
319
 * @method
320
 * @memberof Popper.Utils
321
 * @returns {Boolean} isIE10
322
 */
323
var isIE10 = undefined;
0 ignored issues
show
Unused Code Comprehensibility introduced by
The assignment of undefined is not necessary as isIE10 is implicitly marked as undefined by the declaration.
Loading history...
324
325
var isIE10$1 = function () {
326
  if (isIE10 === undefined) {
327
    isIE10 = navigator.appVersion.indexOf('MSIE 10') !== -1;
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
328
  }
329
  return isIE10;
330
};
331
332
function getSize(axis, body, html, computedStyle) {
333
  return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE10$1() ? html['offset' + axis] + computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')] + computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')] : 0);
334
}
335
336
function getWindowSizes() {
337
  var body = document.body;
338
  var html = document.documentElement;
339
  var computedStyle = isIE10$1() && getComputedStyle(html);
340
341
  return {
342
    height: getSize('Height', body, html, computedStyle),
343
    width: getSize('Width', body, html, computedStyle)
344
  };
345
}
346
347
var classCallCheck = function (instance, Constructor) {
348
  if (!(instance instanceof Constructor)) {
349
    throw new TypeError("Cannot call a class as a function");
350
  }
351
};
352
353
var createClass = function () {
354
  function defineProperties(target, props) {
355
    for (var i = 0; i < props.length; i++) {
356
      var descriptor = props[i];
357
      descriptor.enumerable = descriptor.enumerable || false;
358
      descriptor.configurable = true;
359
      if ("value" in descriptor) descriptor.writable = true;
360
      Object.defineProperty(target, descriptor.key, descriptor);
361
    }
362
  }
363
364
  return function (Constructor, protoProps, staticProps) {
365
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
366
    if (staticProps) defineProperties(Constructor, staticProps);
367
    return Constructor;
368
  };
369
}();
370
371
372
373
374
375
var defineProperty = function (obj, key, value) {
376
  if (key in obj) {
377
    Object.defineProperty(obj, key, {
378
      value: value,
379
      enumerable: true,
380
      configurable: true,
381
      writable: true
382
    });
383
  } else {
384
    obj[key] = value;
385
  }
386
387
  return obj;
388
};
389
390
var _extends = Object.assign || function (target) {
391
  for (var i = 1; i < arguments.length; i++) {
392
    var source = arguments[i];
393
394
    for (var key in source) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
395
      if (Object.prototype.hasOwnProperty.call(source, key)) {
396
        target[key] = source[key];
397
      }
398
    }
399
  }
400
401
  return target;
402
};
403
404
/**
405
 * Given element offsets, generate an output similar to getBoundingClientRect
406
 * @method
407
 * @memberof Popper.Utils
408
 * @argument {Object} offsets
409
 * @returns {Object} ClientRect like output
410
 */
411
function getClientRect(offsets) {
412
  return _extends({}, offsets, {
413
    right: offsets.left + offsets.width,
414
    bottom: offsets.top + offsets.height
415
  });
416
}
417
418
/**
419
 * Get bounding client rect of given element
420
 * @method
421
 * @memberof Popper.Utils
422
 * @param {HTMLElement} element
423
 * @return {Object} client rect
424
 */
425
function getBoundingClientRect(element) {
426
  var rect = {};
0 ignored issues
show
Unused Code introduced by
The assignment to variable rect seems to be never used. Consider removing it.
Loading history...
427
428
  // IE10 10 FIX: Please, don't ask, the element isn't
429
  // considered in DOM in some circumstances...
430
  // This isn't reproducible in IE10 compatibility mode of IE11
431
  if (isIE10$1()) {
432
    try {
433
      rect = element.getBoundingClientRect();
434
      var scrollTop = getScroll(element, 'top');
435
      var scrollLeft = getScroll(element, 'left');
436
      rect.top += scrollTop;
437
      rect.left += scrollLeft;
438
      rect.bottom += scrollTop;
439
      rect.right += scrollLeft;
440
    } catch (err) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
441
  } else {
442
    rect = element.getBoundingClientRect();
443
  }
444
445
  var result = {
446
    left: rect.left,
447
    top: rect.top,
448
    width: rect.right - rect.left,
449
    height: rect.bottom - rect.top
450
  };
451
452
  // subtract scrollbar size from sizes
453
  var sizes = element.nodeName === 'HTML' ? getWindowSizes() : {};
454
  var width = sizes.width || element.clientWidth || result.right - result.left;
455
  var height = sizes.height || element.clientHeight || result.bottom - result.top;
456
457
  var horizScrollbar = element.offsetWidth - width;
458
  var vertScrollbar = element.offsetHeight - height;
459
460
  // if an hypothetical scrollbar is detected, we must be sure it's not a `border`
461
  // we make this check conditional for performance reasons
462
  if (horizScrollbar || vertScrollbar) {
463
    var styles = getStyleComputedProperty(element);
464
    horizScrollbar -= getBordersSize(styles, 'x');
465
    vertScrollbar -= getBordersSize(styles, 'y');
466
467
    result.width -= horizScrollbar;
468
    result.height -= vertScrollbar;
469
  }
470
471
  return getClientRect(result);
472
}
473
474
function getOffsetRectRelativeToArbitraryNode(children, parent) {
475
  var isIE10 = isIE10$1();
476
  var isHTML = parent.nodeName === 'HTML';
477
  var childrenRect = getBoundingClientRect(children);
478
  var parentRect = getBoundingClientRect(parent);
479
  var scrollParent = getScrollParent(children);
480
481
  var styles = getStyleComputedProperty(parent);
482
  var borderTopWidth = parseFloat(styles.borderTopWidth, 10);
483
  var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10);
484
485
  var offsets = getClientRect({
486
    top: childrenRect.top - parentRect.top - borderTopWidth,
487
    left: childrenRect.left - parentRect.left - borderLeftWidth,
488
    width: childrenRect.width,
489
    height: childrenRect.height
490
  });
491
  offsets.marginTop = 0;
492
  offsets.marginLeft = 0;
493
494
  // Subtract margins of documentElement in case it's being used as parent
495
  // we do this only on HTML because it's the only element that behaves
496
  // differently when margins are applied to it. The margins are included in
497
  // the box of the documentElement, in the other cases not.
498
  if (!isIE10 && isHTML) {
499
    var marginTop = parseFloat(styles.marginTop, 10);
500
    var marginLeft = parseFloat(styles.marginLeft, 10);
501
502
    offsets.top -= borderTopWidth - marginTop;
503
    offsets.bottom -= borderTopWidth - marginTop;
504
    offsets.left -= borderLeftWidth - marginLeft;
505
    offsets.right -= borderLeftWidth - marginLeft;
506
507
    // Attach marginTop and marginLeft because in some circumstances we may need them
508
    offsets.marginTop = marginTop;
509
    offsets.marginLeft = marginLeft;
510
  }
511
512
  if (isIE10 ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
513
    offsets = includeScroll(offsets, parent);
514
  }
515
516
  return offsets;
517
}
518
519
function getViewportOffsetRectRelativeToArtbitraryNode(element) {
520
  var html = element.ownerDocument.documentElement;
521
  var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
522
  var width = Math.max(html.clientWidth, window.innerWidth || 0);
523
  var height = Math.max(html.clientHeight, window.innerHeight || 0);
524
525
  var scrollTop = getScroll(html);
526
  var scrollLeft = getScroll(html, 'left');
527
528
  var offset = {
529
    top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
530
    left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,
531
    width: width,
532
    height: height
533
  };
534
535
  return getClientRect(offset);
536
}
537
538
/**
539
 * Check if the given element is fixed or is inside a fixed parent
540
 * @method
541
 * @memberof Popper.Utils
542
 * @argument {Element} element
543
 * @argument {Element} customContainer
544
 * @returns {Boolean} answer to "isFixed?"
545
 */
546
function isFixed(element) {
547
  var nodeName = element.nodeName;
548
  if (nodeName === 'BODY' || nodeName === 'HTML') {
549
    return false;
550
  }
551
  if (getStyleComputedProperty(element, 'position') === 'fixed') {
552
    return true;
553
  }
554
  return isFixed(getParentNode(element));
555
}
556
557
/**
558
 * Computed the boundaries limits and return them
559
 * @method
560
 * @memberof Popper.Utils
561
 * @param {HTMLElement} popper
562
 * @param {HTMLElement} reference
563
 * @param {number} padding
564
 * @param {HTMLElement} boundariesElement - Element used to define the boundaries
565
 * @returns {Object} Coordinates of the boundaries
566
 */
567
function getBoundaries(popper, reference, padding, boundariesElement) {
568
  // NOTE: 1 DOM access here
569
  var boundaries = { top: 0, left: 0 };
570
  var offsetParent = findCommonOffsetParent(popper, reference);
571
572
  // Handle viewport case
573
  if (boundariesElement === 'viewport') {
574
    boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent);
575
  } else {
576
    // Handle other cases based on DOM element used as boundaries
577
    var boundariesNode = void 0;
0 ignored issues
show
Unused Code introduced by
The assignment to variable boundariesNode seems to be never used. Consider removing it.
Loading history...
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
578
    if (boundariesElement === 'scrollParent') {
579
      boundariesNode = getScrollParent(getParentNode(reference));
580
      if (boundariesNode.nodeName === 'BODY') {
581
        boundariesNode = popper.ownerDocument.documentElement;
582
      }
583
    } else if (boundariesElement === 'window') {
584
      boundariesNode = popper.ownerDocument.documentElement;
585
    } else {
586
      boundariesNode = boundariesElement;
587
    }
588
589
    var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent);
590
591
    // In case of HTML, we need a different computation
592
    if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
593
      var _getWindowSizes = getWindowSizes(),
594
          height = _getWindowSizes.height,
595
          width = _getWindowSizes.width;
596
597
      boundaries.top += offsets.top - offsets.marginTop;
598
      boundaries.bottom = height + offsets.top;
599
      boundaries.left += offsets.left - offsets.marginLeft;
600
      boundaries.right = width + offsets.left;
601
    } else {
602
      // for all the other DOM elements, this one is good
603
      boundaries = offsets;
604
    }
605
  }
606
607
  // Add paddings
608
  boundaries.left += padding;
609
  boundaries.top += padding;
610
  boundaries.right -= padding;
611
  boundaries.bottom -= padding;
612
613
  return boundaries;
614
}
615
616
function getArea(_ref) {
617
  var width = _ref.width,
618
      height = _ref.height;
619
620
  return width * height;
621
}
622
623
/**
624
 * Utility used to transform the `auto` placement to the placement with more
625
 * available space.
626
 * @method
627
 * @memberof Popper.Utils
628
 * @argument {Object} data - The data object generated by update method
629
 * @argument {Object} options - Modifiers configuration and options
630
 * @returns {Object} The data object, properly modified
631
 */
632
function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {
633
  var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
634
635
  if (placement.indexOf('auto') === -1) {
636
    return placement;
637
  }
638
639
  var boundaries = getBoundaries(popper, reference, padding, boundariesElement);
640
641
  var rects = {
642
    top: {
643
      width: boundaries.width,
644
      height: refRect.top - boundaries.top
645
    },
646
    right: {
647
      width: boundaries.right - refRect.right,
648
      height: boundaries.height
649
    },
650
    bottom: {
651
      width: boundaries.width,
652
      height: boundaries.bottom - refRect.bottom
653
    },
654
    left: {
655
      width: refRect.left - boundaries.left,
656
      height: boundaries.height
657
    }
658
  };
659
660
  var sortedAreas = Object.keys(rects).map(function (key) {
661
    return _extends({
662
      key: key
663
    }, rects[key], {
664
      area: getArea(rects[key])
665
    });
666
  }).sort(function (a, b) {
667
    return b.area - a.area;
668
  });
669
670
  var filteredAreas = sortedAreas.filter(function (_ref2) {
671
    var width = _ref2.width,
672
        height = _ref2.height;
673
    return width >= popper.clientWidth && height >= popper.clientHeight;
674
  });
675
676
  var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;
677
678
  var variation = placement.split('-')[1];
679
680
  return computedPlacement + (variation ? '-' + variation : '');
681
}
682
683
/**
684
 * Get offsets to the reference element
685
 * @method
686
 * @memberof Popper.Utils
687
 * @param {Object} state
688
 * @param {Element} popper - the popper element
689
 * @param {Element} reference - the reference element (the popper will be relative to this)
690
 * @returns {Object} An object containing the offsets which will be applied to the popper
691
 */
692
function getReferenceOffsets(state, popper, reference) {
693
  var commonOffsetParent = findCommonOffsetParent(popper, reference);
694
  return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent);
695
}
696
697
/**
698
 * Get the outer sizes of the given element (offset size + margins)
699
 * @method
700
 * @memberof Popper.Utils
701
 * @argument {Element} element
702
 * @returns {Object} object containing width and height properties
703
 */
704
function getOuterSizes(element) {
705
  var styles = getComputedStyle(element);
706
  var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom);
707
  var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight);
708
  var result = {
709
    width: element.offsetWidth + y,
710
    height: element.offsetHeight + x
711
  };
712
  return result;
713
}
714
715
/**
716
 * Get the opposite placement of the given one
717
 * @method
718
 * @memberof Popper.Utils
719
 * @argument {String} placement
720
 * @returns {String} flipped placement
721
 */
722
function getOppositePlacement(placement) {
723
  var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
724
  return placement.replace(/left|right|bottom|top/g, function (matched) {
725
    return hash[matched];
726
  });
727
}
728
729
/**
730
 * Get offsets to the popper
731
 * @method
732
 * @memberof Popper.Utils
733
 * @param {Object} position - CSS position the Popper will get applied
734
 * @param {HTMLElement} popper - the popper element
735
 * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
736
 * @param {String} placement - one of the valid placement options
737
 * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
738
 */
739
function getPopperOffsets(popper, referenceOffsets, placement) {
740
  placement = placement.split('-')[0];
741
742
  // Get popper node sizes
743
  var popperRect = getOuterSizes(popper);
744
745
  // Add position, width and height to our offsets object
746
  var popperOffsets = {
747
    width: popperRect.width,
748
    height: popperRect.height
749
  };
750
751
  // depending by the popper placement we have to compute its offsets slightly differently
752
  var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
753
  var mainSide = isHoriz ? 'top' : 'left';
754
  var secondarySide = isHoriz ? 'left' : 'top';
755
  var measurement = isHoriz ? 'height' : 'width';
756
  var secondaryMeasurement = !isHoriz ? 'height' : 'width';
757
758
  popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
759
  if (placement === secondarySide) {
760
    popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
761
  } else {
762
    popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
763
  }
764
765
  return popperOffsets;
766
}
767
768
/**
769
 * Mimics the `find` method of Array
770
 * @method
771
 * @memberof Popper.Utils
772
 * @argument {Array} arr
773
 * @argument prop
774
 * @argument value
775
 * @returns index or -1
776
 */
777
function find(arr, check) {
778
  // use native find if supported
779
  if (Array.prototype.find) {
780
    return arr.find(check);
781
  }
782
783
  // use `filter` to obtain the same behavior of `find`
784
  return arr.filter(check)[0];
785
}
786
787
/**
788
 * Return the index of the matching object
789
 * @method
790
 * @memberof Popper.Utils
791
 * @argument {Array} arr
792
 * @argument prop
793
 * @argument value
794
 * @returns index or -1
795
 */
796
function findIndex(arr, prop, value) {
797
  // use native findIndex if supported
798
  if (Array.prototype.findIndex) {
799
    return arr.findIndex(function (cur) {
800
      return cur[prop] === value;
801
    });
802
  }
803
804
  // use `find` + `indexOf` if `findIndex` isn't supported
805
  var match = find(arr, function (obj) {
806
    return obj[prop] === value;
807
  });
808
  return arr.indexOf(match);
809
}
810
811
/**
812
 * Loop trough the list of modifiers and run them in order,
813
 * each of them will then edit the data object.
814
 * @method
815
 * @memberof Popper.Utils
816
 * @param {dataObject} data
817
 * @param {Array} modifiers
818
 * @param {String} ends - Optional modifier name used as stopper
819
 * @returns {dataObject}
820
 */
821
function runModifiers(modifiers, data, ends) {
822
  var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));
823
824
  modifiersToRun.forEach(function (modifier) {
825
    if (modifier['function']) {
826
      // eslint-disable-line dot-notation
827
      console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
828
    }
829
    var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
830
    if (modifier.enabled && isFunction(fn)) {
831
      // Add properties to offsets to make them a complete clientRect object
832
      // we do this before each modifier to make sure the previous one doesn't
833
      // mess with these values
834
      data.offsets.popper = getClientRect(data.offsets.popper);
835
      data.offsets.reference = getClientRect(data.offsets.reference);
836
837
      data = fn(data, modifier);
838
    }
839
  });
840
841
  return data;
842
}
843
844
/**
845
 * Updates the position of the popper, computing the new offsets and applying
846
 * the new style.<br />
847
 * Prefer `scheduleUpdate` over `update` because of performance reasons.
848
 * @method
849
 * @memberof Popper
850
 */
851
function update() {
852
  // if popper is destroyed, don't perform any further update
853
  if (this.state.isDestroyed) {
854
    return;
855
  }
856
857
  var data = {
858
    instance: this,
859
    styles: {},
860
    arrowStyles: {},
861
    attributes: {},
862
    flipped: false,
863
    offsets: {}
864
  };
865
866
  // compute reference element offsets
867
  data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference);
868
869
  // compute auto placement, store placement inside the data object,
870
  // modifiers will be able to edit `placement` if needed
871
  // and refer to originalPlacement to know the original value
872
  data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);
873
874
  // store the computed placement inside `originalPlacement`
875
  data.originalPlacement = data.placement;
876
877
  // compute the popper offsets
878
  data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);
879
  data.offsets.popper.position = 'absolute';
880
881
  // run the modifiers
882
  data = runModifiers(this.modifiers, data);
883
884
  // the first `update` will call `onCreate` callback
885
  // the other ones will call `onUpdate` callback
886
  if (!this.state.isCreated) {
887
    this.state.isCreated = true;
888
    this.options.onCreate(data);
889
  } else {
890
    this.options.onUpdate(data);
891
  }
892
}
893
894
/**
895
 * Helper used to know if the given modifier is enabled.
896
 * @method
897
 * @memberof Popper.Utils
898
 * @returns {Boolean}
899
 */
900
function isModifierEnabled(modifiers, modifierName) {
901
  return modifiers.some(function (_ref) {
902
    var name = _ref.name,
903
        enabled = _ref.enabled;
904
    return enabled && name === modifierName;
905
  });
906
}
907
908
/**
909
 * Get the prefixed supported property name
910
 * @method
911
 * @memberof Popper.Utils
912
 * @argument {String} property (camelCase)
913
 * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
914
 */
915
function getSupportedPropertyName(property) {
916
  var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
917
  var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
918
919
  for (var i = 0; i < prefixes.length - 1; i++) {
920
    var prefix = prefixes[i];
921
    var toCheck = prefix ? '' + prefix + upperProp : property;
922
    if (typeof document.body.style[toCheck] !== 'undefined') {
923
      return toCheck;
924
    }
925
  }
926
  return null;
927
}
928
929
/**
930
 * Destroy the popper
931
 * @method
932
 * @memberof Popper
933
 */
934
function destroy() {
935
  this.state.isDestroyed = true;
936
937
  // touch DOM only if `applyStyle` modifier is enabled
938
  if (isModifierEnabled(this.modifiers, 'applyStyle')) {
939
    this.popper.removeAttribute('x-placement');
940
    this.popper.style.left = '';
941
    this.popper.style.position = '';
942
    this.popper.style.top = '';
943
    this.popper.style[getSupportedPropertyName('transform')] = '';
944
  }
945
946
  this.disableEventListeners();
947
948
  // remove the popper if user explicity asked for the deletion on destroy
949
  // do not use `remove` because IE11 doesn't support it
950
  if (this.options.removeOnDestroy) {
951
    this.popper.parentNode.removeChild(this.popper);
952
  }
953
  return this;
954
}
955
956
/**
957
 * Get the window associated with the element
958
 * @argument {Element} element
959
 * @returns {Window}
960
 */
961
function getWindow(element) {
962
  var ownerDocument = element.ownerDocument;
963
  return ownerDocument ? ownerDocument.defaultView : window;
964
}
965
966
function attachToScrollParents(scrollParent, event, callback, scrollParents) {
967
  var isBody = scrollParent.nodeName === 'BODY';
968
  var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
969
  target.addEventListener(event, callback, { passive: true });
970
971
  if (!isBody) {
972
    attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
973
  }
974
  scrollParents.push(target);
975
}
976
977
/**
978
 * Setup needed event listeners used to update the popper position
979
 * @method
980
 * @memberof Popper.Utils
981
 * @private
982
 */
983
function setupEventListeners(reference, options, state, updateBound) {
984
  // Resize event listener on window
985
  state.updateBound = updateBound;
986
  getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });
987
988
  // Scroll event listener on scroll parents
989
  var scrollElement = getScrollParent(reference);
990
  attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
991
  state.scrollElement = scrollElement;
992
  state.eventsEnabled = true;
993
994
  return state;
995
}
996
997
/**
998
 * It will add resize/scroll events and start recalculating
999
 * position of the popper element when they are triggered.
1000
 * @method
1001
 * @memberof Popper
1002
 */
1003
function enableEventListeners() {
1004
  if (!this.state.eventsEnabled) {
1005
    this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);
1006
  }
1007
}
1008
1009
/**
1010
 * Remove event listeners used to update the popper position
1011
 * @method
1012
 * @memberof Popper.Utils
1013
 * @private
1014
 */
1015
function removeEventListeners(reference, state) {
1016
  // Remove resize event listener on window
1017
  getWindow(reference).removeEventListener('resize', state.updateBound);
1018
1019
  // Remove scroll event listener on scroll parents
1020
  state.scrollParents.forEach(function (target) {
1021
    target.removeEventListener('scroll', state.updateBound);
1022
  });
1023
1024
  // Reset state
1025
  state.updateBound = null;
1026
  state.scrollParents = [];
1027
  state.scrollElement = null;
1028
  state.eventsEnabled = false;
1029
  return state;
1030
}
1031
1032
/**
1033
 * It will remove resize/scroll events and won't recalculate popper position
1034
 * when they are triggered. It also won't trigger onUpdate callback anymore,
1035
 * unless you call `update` method manually.
1036
 * @method
1037
 * @memberof Popper
1038
 */
1039
function disableEventListeners() {
1040
  if (this.state.eventsEnabled) {
1041
    cancelAnimationFrame(this.scheduleUpdate);
1042
    this.state = removeEventListeners(this.reference, this.state);
1043
  }
1044
}
1045
1046
/**
1047
 * Tells if a given input is a number
1048
 * @method
1049
 * @memberof Popper.Utils
1050
 * @param {*} input to check
1051
 * @return {Boolean}
1052
 */
1053
function isNumeric(n) {
1054
  return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
1055
}
1056
1057
/**
1058
 * Set the style to the given popper
1059
 * @method
1060
 * @memberof Popper.Utils
1061
 * @argument {Element} element - Element to apply the style to
1062
 * @argument {Object} styles
1063
 * Object with a list of properties and values which will be applied to the element
1064
 */
1065
function setStyles(element, styles) {
1066
  Object.keys(styles).forEach(function (prop) {
1067
    var unit = '';
1068
    // add unit if the value is numeric and is one of the following
1069
    if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
1070
      unit = 'px';
1071
    }
1072
    element.style[prop] = styles[prop] + unit;
1073
  });
1074
}
1075
1076
/**
1077
 * Set the attributes to the given popper
1078
 * @method
1079
 * @memberof Popper.Utils
1080
 * @argument {Element} element - Element to apply the attributes to
1081
 * @argument {Object} styles
1082
 * Object with a list of properties and values which will be applied to the element
1083
 */
1084
function setAttributes(element, attributes) {
1085
  Object.keys(attributes).forEach(function (prop) {
1086
    var value = attributes[prop];
1087
    if (value !== false) {
1088
      element.setAttribute(prop, attributes[prop]);
1089
    } else {
1090
      element.removeAttribute(prop);
1091
    }
1092
  });
1093
}
1094
1095
/**
1096
 * @function
1097
 * @memberof Modifiers
1098
 * @argument {Object} data - The data object generated by `update` method
1099
 * @argument {Object} data.styles - List of style properties - values to apply to popper element
1100
 * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
1101
 * @argument {Object} options - Modifiers configuration and options
1102
 * @returns {Object} The same data object
1103
 */
1104
function applyStyle(data) {
1105
  // any property present in `data.styles` will be applied to the popper,
1106
  // in this way we can make the 3rd party modifiers add custom styles to it
1107
  // Be aware, modifiers could override the properties defined in the previous
1108
  // lines of this modifier!
1109
  setStyles(data.instance.popper, data.styles);
1110
1111
  // any property present in `data.attributes` will be applied to the popper,
1112
  // they will be set as HTML attributes of the element
1113
  setAttributes(data.instance.popper, data.attributes);
1114
1115
  // if arrowElement is defined and arrowStyles has some properties
1116
  if (data.arrowElement && Object.keys(data.arrowStyles).length) {
1117
    setStyles(data.arrowElement, data.arrowStyles);
1118
  }
1119
1120
  return data;
1121
}
1122
1123
/**
1124
 * Set the x-placement attribute before everything else because it could be used
1125
 * to add margins to the popper margins needs to be calculated to get the
1126
 * correct popper offsets.
1127
 * @method
1128
 * @memberof Popper.modifiers
1129
 * @param {HTMLElement} reference - The reference element used to position the popper
1130
 * @param {HTMLElement} popper - The HTML element used as popper.
1131
 * @param {Object} options - Popper.js options
1132
 */
1133
function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
1134
  // compute reference element offsets
1135
  var referenceOffsets = getReferenceOffsets(state, popper, reference);
1136
1137
  // compute auto placement, store placement inside the data object,
1138
  // modifiers will be able to edit `placement` if needed
1139
  // and refer to originalPlacement to know the original value
1140
  var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);
1141
1142
  popper.setAttribute('x-placement', placement);
1143
1144
  // Apply `position` to popper before anything else because
1145
  // without the position applied we can't guarantee correct computations
1146
  setStyles(popper, { position: 'absolute' });
1147
1148
  return options;
1149
}
1150
1151
/**
1152
 * @function
1153
 * @memberof Modifiers
1154
 * @argument {Object} data - The data object generated by `update` method
1155
 * @argument {Object} options - Modifiers configuration and options
1156
 * @returns {Object} The data object, properly modified
1157
 */
1158
function computeStyle(data, options) {
1159
  var x = options.x,
1160
      y = options.y;
1161
  var popper = data.offsets.popper;
1162
1163
  // Remove this legacy support in Popper.js v2
1164
1165
  var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {
1166
    return modifier.name === 'applyStyle';
1167
  }).gpuAcceleration;
1168
  if (legacyGpuAccelerationOption !== undefined) {
1169
    console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');
1170
  }
1171
  var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;
1172
1173
  var offsetParent = getOffsetParent(data.instance.popper);
1174
  var offsetParentRect = getBoundingClientRect(offsetParent);
1175
1176
  // Styles
1177
  var styles = {
1178
    position: popper.position
1179
  };
1180
1181
  // floor sides to avoid blurry text
1182
  var offsets = {
1183
    left: Math.floor(popper.left),
1184
    top: Math.floor(popper.top),
1185
    bottom: Math.floor(popper.bottom),
1186
    right: Math.floor(popper.right)
1187
  };
1188
1189
  var sideA = x === 'bottom' ? 'top' : 'bottom';
1190
  var sideB = y === 'right' ? 'left' : 'right';
1191
1192
  // if gpuAcceleration is set to `true` and transform is supported,
1193
  //  we use `translate3d` to apply the position to the popper we
1194
  // automatically use the supported prefixed version if needed
1195
  var prefixedProperty = getSupportedPropertyName('transform');
1196
1197
  // now, let's make a step back and look at this code closely (wtf?)
1198
  // If the content of the popper grows once it's been positioned, it
1199
  // may happen that the popper gets misplaced because of the new content
1200
  // overflowing its reference element
1201
  // To avoid this problem, we provide two options (x and y), which allow
1202
  // the consumer to define the offset origin.
1203
  // If we position a popper on top of a reference element, we can set
1204
  // `x` to `top` to make the popper grow towards its top instead of
1205
  // its bottom.
1206
  var left = void 0,
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
1207
      top = void 0;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
1208
  if (sideA === 'bottom') {
1209
    top = -offsetParentRect.height + offsets.bottom;
1210
  } else {
1211
    top = offsets.top;
1212
  }
1213
  if (sideB === 'right') {
1214
    left = -offsetParentRect.width + offsets.right;
1215
  } else {
1216
    left = offsets.left;
1217
  }
1218
  if (gpuAcceleration && prefixedProperty) {
1219
    styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
1220
    styles[sideA] = 0;
1221
    styles[sideB] = 0;
1222
    styles.willChange = 'transform';
1223
  } else {
1224
    // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties
1225
    var invertTop = sideA === 'bottom' ? -1 : 1;
1226
    var invertLeft = sideB === 'right' ? -1 : 1;
1227
    styles[sideA] = top * invertTop;
1228
    styles[sideB] = left * invertLeft;
1229
    styles.willChange = sideA + ', ' + sideB;
1230
  }
1231
1232
  // Attributes
1233
  var attributes = {
1234
    'x-placement': data.placement
1235
  };
1236
1237
  // Update `data` attributes, styles and arrowStyles
1238
  data.attributes = _extends({}, attributes, data.attributes);
1239
  data.styles = _extends({}, styles, data.styles);
1240
  data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);
1241
1242
  return data;
1243
}
1244
1245
/**
1246
 * Helper used to know if the given modifier depends from another one.<br />
1247
 * It checks if the needed modifier is listed and enabled.
1248
 * @method
1249
 * @memberof Popper.Utils
1250
 * @param {Array} modifiers - list of modifiers
1251
 * @param {String} requestingName - name of requesting modifier
1252
 * @param {String} requestedName - name of requested modifier
1253
 * @returns {Boolean}
1254
 */
1255
function isModifierRequired(modifiers, requestingName, requestedName) {
1256
  var requesting = find(modifiers, function (_ref) {
1257
    var name = _ref.name;
1258
    return name === requestingName;
1259
  });
1260
1261
  var isRequired = !!requesting && modifiers.some(function (modifier) {
1262
    return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
1263
  });
1264
1265
  if (!isRequired) {
1266
    var _requesting = '`' + requestingName + '`';
1267
    var requested = '`' + requestedName + '`';
1268
    console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');
1269
  }
1270
  return isRequired;
1271
}
1272
1273
/**
1274
 * @function
1275
 * @memberof Modifiers
1276
 * @argument {Object} data - The data object generated by update method
1277
 * @argument {Object} options - Modifiers configuration and options
1278
 * @returns {Object} The data object, properly modified
1279
 */
1280
function arrow(data, options) {
1281
  var _data$offsets$arrow;
1282
1283
  // arrow depends on keepTogether in order to work
1284
  if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
1285
    return data;
1286
  }
1287
1288
  var arrowElement = options.element;
1289
1290
  // if arrowElement is a string, suppose it's a CSS selector
1291
  if (typeof arrowElement === 'string') {
1292
    arrowElement = data.instance.popper.querySelector(arrowElement);
1293
1294
    // if arrowElement is not found, don't run the modifier
1295
    if (!arrowElement) {
1296
      return data;
1297
    }
1298
  } else {
1299
    // if the arrowElement isn't a query selector we must check that the
1300
    // provided DOM node is child of its popper node
1301
    if (!data.instance.popper.contains(arrowElement)) {
1302
      console.warn('WARNING: `arrow.element` must be child of its popper element!');
1303
      return data;
1304
    }
1305
  }
1306
1307
  var placement = data.placement.split('-')[0];
1308
  var _data$offsets = data.offsets,
1309
      popper = _data$offsets.popper,
1310
      reference = _data$offsets.reference;
1311
1312
  var isVertical = ['left', 'right'].indexOf(placement) !== -1;
1313
1314
  var len = isVertical ? 'height' : 'width';
1315
  var sideCapitalized = isVertical ? 'Top' : 'Left';
1316
  var side = sideCapitalized.toLowerCase();
1317
  var altSide = isVertical ? 'left' : 'top';
1318
  var opSide = isVertical ? 'bottom' : 'right';
1319
  var arrowElementSize = getOuterSizes(arrowElement)[len];
1320
1321
  //
1322
  // extends keepTogether behavior making sure the popper and its
1323
  // reference have enough pixels in conjuction
1324
  //
1325
1326
  // top/left side
1327
  if (reference[opSide] - arrowElementSize < popper[side]) {
1328
    data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);
1329
  }
1330
  // bottom/right side
1331
  if (reference[side] + arrowElementSize > popper[opSide]) {
1332
    data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
1333
  }
1334
  data.offsets.popper = getClientRect(data.offsets.popper);
1335
1336
  // compute center of the popper
1337
  var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;
1338
1339
  // Compute the sideValue using the updated popper offsets
1340
  // take popper margin in account because we don't have this info available
1341
  var css = getStyleComputedProperty(data.instance.popper);
1342
  var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10);
1343
  var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10);
1344
  var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;
1345
1346
  // prevent arrowElement from being placed not contiguously to its popper
1347
  sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);
1348
1349
  data.arrowElement = arrowElement;
1350
  data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
1351
1352
  return data;
1353
}
1354
1355
/**
1356
 * Get the opposite placement variation of the given one
1357
 * @method
1358
 * @memberof Popper.Utils
1359
 * @argument {String} placement variation
1360
 * @returns {String} flipped placement variation
1361
 */
1362
function getOppositeVariation(variation) {
1363
  if (variation === 'end') {
1364
    return 'start';
1365
  } else if (variation === 'start') {
1366
    return 'end';
1367
  }
1368
  return variation;
1369
}
1370
1371
/**
1372
 * List of accepted placements to use as values of the `placement` option.<br />
1373
 * Valid placements are:
1374
 * - `auto`
1375
 * - `top`
1376
 * - `right`
1377
 * - `bottom`
1378
 * - `left`
1379
 *
1380
 * Each placement can have a variation from this list:
1381
 * - `-start`
1382
 * - `-end`
1383
 *
1384
 * Variations are interpreted easily if you think of them as the left to right
1385
 * written languages. Horizontally (`top` and `bottom`), `start` is left and `end`
1386
 * is right.<br />
1387
 * Vertically (`left` and `right`), `start` is top and `end` is bottom.
1388
 *
1389
 * Some valid examples are:
1390
 * - `top-end` (on top of reference, right aligned)
1391
 * - `right-start` (on right of reference, top aligned)
1392
 * - `bottom` (on bottom, centered)
1393
 * - `auto-right` (on the side with more space available, alignment depends by placement)
1394
 *
1395
 * @static
1396
 * @type {Array}
1397
 * @enum {String}
1398
 * @readonly
1399
 * @method placements
1400
 * @memberof Popper
1401
 */
1402
var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];
1403
1404
// Get rid of `auto` `auto-start` and `auto-end`
1405
var validPlacements = placements.slice(3);
1406
1407
/**
1408
 * Given an initial placement, returns all the subsequent placements
1409
 * clockwise (or counter-clockwise).
1410
 *
1411
 * @method
1412
 * @memberof Popper.Utils
1413
 * @argument {String} placement - A valid placement (it accepts variations)
1414
 * @argument {Boolean} counter - Set to true to walk the placements counterclockwise
1415
 * @returns {Array} placements including their variations
1416
 */
1417
function clockwise(placement) {
1418
  var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1419
1420
  var index = validPlacements.indexOf(placement);
1421
  var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));
1422
  return counter ? arr.reverse() : arr;
1423
}
1424
1425
var BEHAVIORS = {
1426
  FLIP: 'flip',
1427
  CLOCKWISE: 'clockwise',
1428
  COUNTERCLOCKWISE: 'counterclockwise'
1429
};
1430
1431
/**
1432
 * @function
1433
 * @memberof Modifiers
1434
 * @argument {Object} data - The data object generated by update method
1435
 * @argument {Object} options - Modifiers configuration and options
1436
 * @returns {Object} The data object, properly modified
1437
 */
1438
function flip(data, options) {
1439
  // if `inner` modifier is enabled, we can't use the `flip` modifier
1440
  if (isModifierEnabled(data.instance.modifiers, 'inner')) {
1441
    return data;
1442
  }
1443
1444
  if (data.flipped && data.placement === data.originalPlacement) {
1445
    // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides
1446
    return data;
1447
  }
1448
1449
  var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement);
1450
1451
  var placement = data.placement.split('-')[0];
1452
  var placementOpposite = getOppositePlacement(placement);
1453
  var variation = data.placement.split('-')[1] || '';
1454
1455
  var flipOrder = [];
0 ignored issues
show
Unused Code introduced by
The assignment to variable flipOrder seems to be never used. Consider removing it.
Loading history...
1456
1457
  switch (options.behavior) {
1458
    case BEHAVIORS.FLIP:
1459
      flipOrder = [placement, placementOpposite];
1460
      break;
1461
    case BEHAVIORS.CLOCKWISE:
1462
      flipOrder = clockwise(placement);
1463
      break;
1464
    case BEHAVIORS.COUNTERCLOCKWISE:
1465
      flipOrder = clockwise(placement, true);
1466
      break;
1467
    default:
1468
      flipOrder = options.behavior;
1469
  }
1470
1471
  flipOrder.forEach(function (step, index) {
1472
    if (placement !== step || flipOrder.length === index + 1) {
1473
      return data;
1474
    }
1475
1476
    placement = data.placement.split('-')[0];
1477
    placementOpposite = getOppositePlacement(placement);
1478
1479
    var popperOffsets = data.offsets.popper;
1480
    var refOffsets = data.offsets.reference;
1481
1482
    // using floor because the reference offsets may contain decimals we are not going to consider here
1483
    var floor = Math.floor;
1484
    var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);
1485
1486
    var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);
1487
    var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);
1488
    var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);
1489
    var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);
1490
1491
    var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;
1492
1493
    // flip the variation if required
1494
    var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
1495
    var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);
1496
1497
    if (overlapsRef || overflowsBoundaries || flippedVariation) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if overlapsRef || overflows...ies || flippedVariation is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
1498
      // this boolean to detect any flip loop
1499
      data.flipped = true;
1500
1501
      if (overlapsRef || overflowsBoundaries) {
1502
        placement = flipOrder[index + 1];
1503
      }
1504
1505
      if (flippedVariation) {
1506
        variation = getOppositeVariation(variation);
1507
      }
1508
1509
      data.placement = placement + (variation ? '-' + variation : '');
1510
1511
      // this object contains `position`, we want to preserve it along with
1512
      // any additional property we may add in the future
1513
      data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
1514
1515
      data = runModifiers(data.instance.modifiers, data, 'flip');
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1516
    }
1517
  });
1518
  return data;
1519
}
1520
1521
/**
1522
 * @function
1523
 * @memberof Modifiers
1524
 * @argument {Object} data - The data object generated by update method
1525
 * @argument {Object} options - Modifiers configuration and options
1526
 * @returns {Object} The data object, properly modified
1527
 */
1528
function keepTogether(data) {
1529
  var _data$offsets = data.offsets,
1530
      popper = _data$offsets.popper,
1531
      reference = _data$offsets.reference;
1532
1533
  var placement = data.placement.split('-')[0];
1534
  var floor = Math.floor;
1535
  var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
1536
  var side = isVertical ? 'right' : 'bottom';
1537
  var opSide = isVertical ? 'left' : 'top';
1538
  var measurement = isVertical ? 'width' : 'height';
1539
1540
  if (popper[side] < floor(reference[opSide])) {
1541
    data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];
1542
  }
1543
  if (popper[opSide] > floor(reference[side])) {
1544
    data.offsets.popper[opSide] = floor(reference[side]);
1545
  }
1546
1547
  return data;
1548
}
1549
1550
/**
1551
 * Converts a string containing value + unit into a px value number
1552
 * @function
1553
 * @memberof {modifiers~offset}
1554
 * @private
1555
 * @argument {String} str - Value + unit string
1556
 * @argument {String} measurement - `height` or `width`
1557
 * @argument {Object} popperOffsets
1558
 * @argument {Object} referenceOffsets
1559
 * @returns {Number|String}
1560
 * Value in pixels, or original string if no values were extracted
1561
 */
1562
function toValue(str, measurement, popperOffsets, referenceOffsets) {
1563
  // separate value from unit
1564
  var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/);
1565
  var value = +split[1];
1566
  var unit = split[2];
1567
1568
  // If it's not a number it's an operator, I guess
1569
  if (!value) {
1570
    return str;
1571
  }
1572
1573
  if (unit.indexOf('%') === 0) {
1574
    var element = void 0;
0 ignored issues
show
Unused Code introduced by
The assignment to variable element seems to be never used. Consider removing it.
Loading history...
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
1575
    switch (unit) {
1576
      case '%p':
1577
        element = popperOffsets;
1578
        break;
1579
      case '%':
1580
      case '%r':
1581
      default:
1582
        element = referenceOffsets;
1583
    }
1584
1585
    var rect = getClientRect(element);
1586
    return rect[measurement] / 100 * value;
1587
  } else if (unit === 'vh' || unit === 'vw') {
1588
    // if is a vh or vw, we calculate the size based on the viewport
1589
    var size = void 0;
0 ignored issues
show
Unused Code introduced by
The assignment to variable size seems to be never used. Consider removing it.
Loading history...
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
1590
    if (unit === 'vh') {
1591
      size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
1592
    } else {
1593
      size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
1594
    }
1595
    return size / 100 * value;
1596
  } else {
1597
    // if is an explicit pixel unit, we get rid of the unit and keep the value
1598
    // if is an implicit unit, it's px, and we return just the value
1599
    return value;
1600
  }
1601
}
1602
1603
/**
1604
 * Parse an `offset` string to extrapolate `x` and `y` numeric offsets.
1605
 * @function
1606
 * @memberof {modifiers~offset}
1607
 * @private
1608
 * @argument {String} offset
1609
 * @argument {Object} popperOffsets
1610
 * @argument {Object} referenceOffsets
1611
 * @argument {String} basePlacement
1612
 * @returns {Array} a two cells array with x and y offsets in numbers
1613
 */
1614
function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
1615
  var offsets = [0, 0];
1616
1617
  // Use height if placement is left or right and index is 0 otherwise use width
1618
  // in this way the first offset will use an axis and the second one
1619
  // will use the other one
1620
  var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;
1621
1622
  // Split the offset string to obtain a list of values and operands
1623
  // The regex addresses values with the plus or minus sign in front (+10, -20, etc)
1624
  var fragments = offset.split(/(\+|\-)/).map(function (frag) {
1625
    return frag.trim();
1626
  });
1627
1628
  // Detect if the offset string contains a pair of values or a single one
1629
  // they could be separated by comma or space
1630
  var divider = fragments.indexOf(find(fragments, function (frag) {
1631
    return frag.search(/,|\s/) !== -1;
1632
  }));
1633
1634
  if (fragments[divider] && fragments[divider].indexOf(',') === -1) {
1635
    console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');
1636
  }
1637
1638
  // If divider is found, we divide the list of values and operands to divide
1639
  // them by ofset X and Y.
1640
  var splitRegex = /\s*,\s*|\s+/;
1641
  var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];
1642
1643
  // Convert the values with units to absolute pixels to allow our computations
1644
  ops = ops.map(function (op, index) {
1645
    // Most of the units rely on the orientation of the popper
1646
    var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';
1647
    var mergeWithPrevious = false;
1648
    return op
1649
    // This aggregates any `+` or `-` sign that aren't considered operators
1650
    // e.g.: 10 + +5 => [10, +, +5]
1651
    .reduce(function (a, b) {
1652
      if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {
1653
        a[a.length - 1] = b;
1654
        mergeWithPrevious = true;
1655
        return a;
1656
      } else if (mergeWithPrevious) {
1657
        a[a.length - 1] += b;
1658
        mergeWithPrevious = false;
1659
        return a;
1660
      } else {
1661
        return a.concat(b);
1662
      }
1663
    }, [])
1664
    // Here we convert the string values into number values (in px)
1665
    .map(function (str) {
1666
      return toValue(str, measurement, popperOffsets, referenceOffsets);
1667
    });
1668
  });
1669
1670
  // Loop trough the offsets arrays and execute the operations
1671
  ops.forEach(function (op, index) {
1672
    op.forEach(function (frag, index2) {
1673
      if (isNumeric(frag)) {
1674
        offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);
1675
      }
1676
    });
1677
  });
1678
  return offsets;
1679
}
1680
1681
/**
1682
 * @function
1683
 * @memberof Modifiers
1684
 * @argument {Object} data - The data object generated by update method
1685
 * @argument {Object} options - Modifiers configuration and options
1686
 * @argument {Number|String} options.offset=0
1687
 * The offset value as described in the modifier description
1688
 * @returns {Object} The data object, properly modified
1689
 */
1690
function offset(data, _ref) {
1691
  var offset = _ref.offset;
1692
  var placement = data.placement,
1693
      _data$offsets = data.offsets,
1694
      popper = _data$offsets.popper,
1695
      reference = _data$offsets.reference;
1696
1697
  var basePlacement = placement.split('-')[0];
1698
1699
  var offsets = void 0;
0 ignored issues
show
Unused Code introduced by
The assignment to variable offsets seems to be never used. Consider removing it.
Loading history...
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
1700
  if (isNumeric(+offset)) {
1701
    offsets = [+offset, 0];
1702
  } else {
1703
    offsets = parseOffset(offset, popper, reference, basePlacement);
1704
  }
1705
1706
  if (basePlacement === 'left') {
1707
    popper.top += offsets[0];
1708
    popper.left -= offsets[1];
1709
  } else if (basePlacement === 'right') {
1710
    popper.top += offsets[0];
1711
    popper.left += offsets[1];
1712
  } else if (basePlacement === 'top') {
1713
    popper.left += offsets[0];
1714
    popper.top -= offsets[1];
1715
  } else if (basePlacement === 'bottom') {
1716
    popper.left += offsets[0];
1717
    popper.top += offsets[1];
1718
  }
1719
1720
  data.popper = popper;
1721
  return data;
1722
}
1723
1724
/**
1725
 * @function
1726
 * @memberof Modifiers
1727
 * @argument {Object} data - The data object generated by `update` method
1728
 * @argument {Object} options - Modifiers configuration and options
1729
 * @returns {Object} The data object, properly modified
1730
 */
1731
function preventOverflow(data, options) {
1732
  var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);
1733
1734
  // If offsetParent is the reference element, we really want to
1735
  // go one step up and use the next offsetParent as reference to
1736
  // avoid to make this modifier completely useless and look like broken
1737
  if (data.instance.reference === boundariesElement) {
1738
    boundariesElement = getOffsetParent(boundariesElement);
1739
  }
1740
1741
  var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement);
1742
  options.boundaries = boundaries;
1743
1744
  var order = options.priority;
1745
  var popper = data.offsets.popper;
1746
1747
  var check = {
1748
    primary: function primary(placement) {
1749
      var value = popper[placement];
1750
      if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
1751
        value = Math.max(popper[placement], boundaries[placement]);
1752
      }
1753
      return defineProperty({}, placement, value);
1754
    },
1755
    secondary: function secondary(placement) {
1756
      var mainSide = placement === 'right' ? 'left' : 'top';
1757
      var value = popper[mainSide];
1758
      if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
1759
        value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
1760
      }
1761
      return defineProperty({}, mainSide, value);
1762
    }
1763
  };
1764
1765
  order.forEach(function (placement) {
1766
    var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
1767
    popper = _extends({}, popper, check[side](placement));
1768
  });
1769
1770
  data.offsets.popper = popper;
1771
1772
  return data;
1773
}
1774
1775
/**
1776
 * @function
1777
 * @memberof Modifiers
1778
 * @argument {Object} data - The data object generated by `update` method
1779
 * @argument {Object} options - Modifiers configuration and options
1780
 * @returns {Object} The data object, properly modified
1781
 */
1782
function shift(data) {
1783
  var placement = data.placement;
1784
  var basePlacement = placement.split('-')[0];
1785
  var shiftvariation = placement.split('-')[1];
1786
1787
  // if shift shiftvariation is specified, run the modifier
1788
  if (shiftvariation) {
1789
    var _data$offsets = data.offsets,
1790
        reference = _data$offsets.reference,
1791
        popper = _data$offsets.popper;
1792
1793
    var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;
1794
    var side = isVertical ? 'left' : 'top';
1795
    var measurement = isVertical ? 'width' : 'height';
1796
1797
    var shiftOffsets = {
1798
      start: defineProperty({}, side, reference[side]),
1799
      end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
1800
    };
1801
1802
    data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
1803
  }
1804
1805
  return data;
1806
}
1807
1808
/**
1809
 * @function
1810
 * @memberof Modifiers
1811
 * @argument {Object} data - The data object generated by update method
1812
 * @argument {Object} options - Modifiers configuration and options
1813
 * @returns {Object} The data object, properly modified
1814
 */
1815
function hide(data) {
1816
  if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {
1817
    return data;
1818
  }
1819
1820
  var refRect = data.offsets.reference;
1821
  var bound = find(data.instance.modifiers, function (modifier) {
1822
    return modifier.name === 'preventOverflow';
1823
  }).boundaries;
1824
1825
  if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {
1826
    // Avoid unnecessary DOM access if visibility hasn't changed
1827
    if (data.hide === true) {
1828
      return data;
1829
    }
1830
1831
    data.hide = true;
1832
    data.attributes['x-out-of-boundaries'] = '';
1833
  } else {
1834
    // Avoid unnecessary DOM access if visibility hasn't changed
1835
    if (data.hide === false) {
1836
      return data;
1837
    }
1838
1839
    data.hide = false;
1840
    data.attributes['x-out-of-boundaries'] = false;
1841
  }
1842
1843
  return data;
1844
}
1845
1846
/**
1847
 * @function
1848
 * @memberof Modifiers
1849
 * @argument {Object} data - The data object generated by `update` method
1850
 * @argument {Object} options - Modifiers configuration and options
1851
 * @returns {Object} The data object, properly modified
1852
 */
1853
function inner(data) {
1854
  var placement = data.placement;
1855
  var basePlacement = placement.split('-')[0];
1856
  var _data$offsets = data.offsets,
1857
      popper = _data$offsets.popper,
1858
      reference = _data$offsets.reference;
1859
1860
  var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;
1861
1862
  var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;
1863
1864
  popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);
1865
1866
  data.placement = getOppositePlacement(placement);
1867
  data.offsets.popper = getClientRect(popper);
1868
1869
  return data;
1870
}
1871
1872
/**
1873
 * Modifier function, each modifier can have a function of this type assigned
1874
 * to its `fn` property.<br />
1875
 * These functions will be called on each update, this means that you must
1876
 * make sure they are performant enough to avoid performance bottlenecks.
1877
 *
1878
 * @function ModifierFn
1879
 * @argument {dataObject} data - The data object generated by `update` method
1880
 * @argument {Object} options - Modifiers configuration and options
1881
 * @returns {dataObject} The data object, properly modified
1882
 */
1883
1884
/**
1885
 * Modifiers are plugins used to alter the behavior of your poppers.<br />
1886
 * Popper.js uses a set of 9 modifiers to provide all the basic functionalities
1887
 * needed by the library.
1888
 *
1889
 * Usually you don't want to override the `order`, `fn` and `onLoad` props.
1890
 * All the other properties are configurations that could be tweaked.
1891
 * @namespace modifiers
1892
 */
1893
var modifiers = {
1894
  /**
1895
   * Modifier used to shift the popper on the start or end of its reference
1896
   * element.<br />
1897
   * It will read the variation of the `placement` property.<br />
1898
   * It can be one either `-end` or `-start`.
1899
   * @memberof modifiers
1900
   * @inner
1901
   */
1902
  shift: {
1903
    /** @prop {number} order=100 - Index used to define the order of execution */
1904
    order: 100,
1905
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
1906
    enabled: true,
1907
    /** @prop {ModifierFn} */
1908
    fn: shift
1909
  },
1910
1911
  /**
1912
   * The `offset` modifier can shift your popper on both its axis.
1913
   *
1914
   * It accepts the following units:
1915
   * - `px` or unitless, interpreted as pixels
1916
   * - `%` or `%r`, percentage relative to the length of the reference element
1917
   * - `%p`, percentage relative to the length of the popper element
1918
   * - `vw`, CSS viewport width unit
1919
   * - `vh`, CSS viewport height unit
1920
   *
1921
   * For length is intended the main axis relative to the placement of the popper.<br />
1922
   * This means that if the placement is `top` or `bottom`, the length will be the
1923
   * `width`. In case of `left` or `right`, it will be the height.
1924
   *
1925
   * You can provide a single value (as `Number` or `String`), or a pair of values
1926
   * as `String` divided by a comma or one (or more) white spaces.<br />
1927
   * The latter is a deprecated method because it leads to confusion and will be
1928
   * removed in v2.<br />
1929
   * Additionally, it accepts additions and subtractions between different units.
1930
   * Note that multiplications and divisions aren't supported.
1931
   *
1932
   * Valid examples are:
1933
   * ```
1934
   * 10
1935
   * '10%'
1936
   * '10, 10'
1937
   * '10%, 10'
1938
   * '10 + 10%'
1939
   * '10 - 5vh + 3%'
1940
   * '-10px + 5vh, 5px - 6%'
1941
   * ```
1942
   * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
1943
   * > with their reference element, unfortunately, you will have to disable the `flip` modifier.
1944
   * > More on this [reading this issue](https://github.com/FezVrasta/popper.js/issues/373)
1945
   *
1946
   * @memberof modifiers
1947
   * @inner
1948
   */
1949
  offset: {
1950
    /** @prop {number} order=200 - Index used to define the order of execution */
1951
    order: 200,
1952
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
1953
    enabled: true,
1954
    /** @prop {ModifierFn} */
1955
    fn: offset,
1956
    /** @prop {Number|String} offset=0
1957
     * The offset value as described in the modifier description
1958
     */
1959
    offset: 0
1960
  },
1961
1962
  /**
1963
   * Modifier used to prevent the popper from being positioned outside the boundary.
1964
   *
1965
   * An scenario exists where the reference itself is not within the boundaries.<br />
1966
   * We can say it has "escaped the boundaries" — or just "escaped".<br />
1967
   * In this case we need to decide whether the popper should either:
1968
   *
1969
   * - detach from the reference and remain "trapped" in the boundaries, or
1970
   * - if it should ignore the boundary and "escape with its reference"
1971
   *
1972
   * When `escapeWithReference` is set to`true` and reference is completely
1973
   * outside its boundaries, the popper will overflow (or completely leave)
1974
   * the boundaries in order to remain attached to the edge of the reference.
1975
   *
1976
   * @memberof modifiers
1977
   * @inner
1978
   */
1979
  preventOverflow: {
1980
    /** @prop {number} order=300 - Index used to define the order of execution */
1981
    order: 300,
1982
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
1983
    enabled: true,
1984
    /** @prop {ModifierFn} */
1985
    fn: preventOverflow,
1986
    /**
1987
     * @prop {Array} [priority=['left','right','top','bottom']]
1988
     * Popper will try to prevent overflow following these priorities by default,
1989
     * then, it could overflow on the left and on top of the `boundariesElement`
1990
     */
1991
    priority: ['left', 'right', 'top', 'bottom'],
1992
    /**
1993
     * @prop {number} padding=5
1994
     * Amount of pixel used to define a minimum distance between the boundaries
1995
     * and the popper this makes sure the popper has always a little padding
1996
     * between the edges of its container
1997
     */
1998
    padding: 5,
1999
    /**
2000
     * @prop {String|HTMLElement} boundariesElement='scrollParent'
2001
     * Boundaries used by the modifier, can be `scrollParent`, `window`,
2002
     * `viewport` or any DOM element.
2003
     */
2004
    boundariesElement: 'scrollParent'
2005
  },
2006
2007
  /**
2008
   * Modifier used to make sure the reference and its popper stay near eachothers
2009
   * without leaving any gap between the two. Expecially useful when the arrow is
2010
   * enabled and you want to assure it to point to its reference element.
2011
   * It cares only about the first axis, you can still have poppers with margin
2012
   * between the popper and its reference element.
2013
   * @memberof modifiers
2014
   * @inner
2015
   */
2016
  keepTogether: {
2017
    /** @prop {number} order=400 - Index used to define the order of execution */
2018
    order: 400,
2019
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2020
    enabled: true,
2021
    /** @prop {ModifierFn} */
2022
    fn: keepTogether
2023
  },
2024
2025
  /**
2026
   * This modifier is used to move the `arrowElement` of the popper to make
2027
   * sure it is positioned between the reference element and its popper element.
2028
   * It will read the outer size of the `arrowElement` node to detect how many
2029
   * pixels of conjuction are needed.
2030
   *
2031
   * It has no effect if no `arrowElement` is provided.
2032
   * @memberof modifiers
2033
   * @inner
2034
   */
2035
  arrow: {
2036
    /** @prop {number} order=500 - Index used to define the order of execution */
2037
    order: 500,
2038
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2039
    enabled: true,
2040
    /** @prop {ModifierFn} */
2041
    fn: arrow,
2042
    /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */
2043
    element: '[x-arrow]'
2044
  },
2045
2046
  /**
2047
   * Modifier used to flip the popper's placement when it starts to overlap its
2048
   * reference element.
2049
   *
2050
   * Requires the `preventOverflow` modifier before it in order to work.
2051
   *
2052
   * **NOTE:** this modifier will interrupt the current update cycle and will
2053
   * restart it if it detects the need to flip the placement.
2054
   * @memberof modifiers
2055
   * @inner
2056
   */
2057
  flip: {
2058
    /** @prop {number} order=600 - Index used to define the order of execution */
2059
    order: 600,
2060
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2061
    enabled: true,
2062
    /** @prop {ModifierFn} */
2063
    fn: flip,
2064
    /**
2065
     * @prop {String|Array} behavior='flip'
2066
     * The behavior used to change the popper's placement. It can be one of
2067
     * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid
2068
     * placements (with optional variations).
2069
     */
2070
    behavior: 'flip',
2071
    /**
2072
     * @prop {number} padding=5
2073
     * The popper will flip if it hits the edges of the `boundariesElement`
2074
     */
2075
    padding: 5,
2076
    /**
2077
     * @prop {String|HTMLElement} boundariesElement='viewport'
2078
     * The element which will define the boundaries of the popper position,
2079
     * the popper will never be placed outside of the defined boundaries
2080
     * (except if keepTogether is enabled)
2081
     */
2082
    boundariesElement: 'viewport'
2083
  },
2084
2085
  /**
2086
   * Modifier used to make the popper flow toward the inner of the reference element.
2087
   * By default, when this modifier is disabled, the popper will be placed outside
2088
   * the reference element.
2089
   * @memberof modifiers
2090
   * @inner
2091
   */
2092
  inner: {
2093
    /** @prop {number} order=700 - Index used to define the order of execution */
2094
    order: 700,
2095
    /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */
2096
    enabled: false,
2097
    /** @prop {ModifierFn} */
2098
    fn: inner
2099
  },
2100
2101
  /**
2102
   * Modifier used to hide the popper when its reference element is outside of the
2103
   * popper boundaries. It will set a `x-out-of-boundaries` attribute which can
2104
   * be used to hide with a CSS selector the popper when its reference is
2105
   * out of boundaries.
2106
   *
2107
   * Requires the `preventOverflow` modifier before it in order to work.
2108
   * @memberof modifiers
2109
   * @inner
2110
   */
2111
  hide: {
2112
    /** @prop {number} order=800 - Index used to define the order of execution */
2113
    order: 800,
2114
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2115
    enabled: true,
2116
    /** @prop {ModifierFn} */
2117
    fn: hide
2118
  },
2119
2120
  /**
2121
   * Computes the style that will be applied to the popper element to gets
2122
   * properly positioned.
2123
   *
2124
   * Note that this modifier will not touch the DOM, it just prepares the styles
2125
   * so that `applyStyle` modifier can apply it. This separation is useful
2126
   * in case you need to replace `applyStyle` with a custom implementation.
2127
   *
2128
   * This modifier has `850` as `order` value to maintain backward compatibility
2129
   * with previous versions of Popper.js. Expect the modifiers ordering method
2130
   * to change in future major versions of the library.
2131
   *
2132
   * @memberof modifiers
2133
   * @inner
2134
   */
2135
  computeStyle: {
2136
    /** @prop {number} order=850 - Index used to define the order of execution */
2137
    order: 850,
2138
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2139
    enabled: true,
2140
    /** @prop {ModifierFn} */
2141
    fn: computeStyle,
2142
    /**
2143
     * @prop {Boolean} gpuAcceleration=true
2144
     * If true, it uses the CSS 3d transformation to position the popper.
2145
     * Otherwise, it will use the `top` and `left` properties.
2146
     */
2147
    gpuAcceleration: true,
2148
    /**
2149
     * @prop {string} [x='bottom']
2150
     * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.
2151
     * Change this if your popper should grow in a direction different from `bottom`
2152
     */
2153
    x: 'bottom',
2154
    /**
2155
     * @prop {string} [x='left']
2156
     * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.
2157
     * Change this if your popper should grow in a direction different from `right`
2158
     */
2159
    y: 'right'
2160
  },
2161
2162
  /**
2163
   * Applies the computed styles to the popper element.
2164
   *
2165
   * All the DOM manipulations are limited to this modifier. This is useful in case
2166
   * you want to integrate Popper.js inside a framework or view library and you
2167
   * want to delegate all the DOM manipulations to it.
2168
   *
2169
   * Note that if you disable this modifier, you must make sure the popper element
2170
   * has its position set to `absolute` before Popper.js can do its work!
2171
   *
2172
   * Just disable this modifier and define you own to achieve the desired effect.
2173
   *
2174
   * @memberof modifiers
2175
   * @inner
2176
   */
2177
  applyStyle: {
2178
    /** @prop {number} order=900 - Index used to define the order of execution */
2179
    order: 900,
2180
    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
2181
    enabled: true,
2182
    /** @prop {ModifierFn} */
2183
    fn: applyStyle,
2184
    /** @prop {Function} */
2185
    onLoad: applyStyleOnLoad,
2186
    /**
2187
     * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier
2188
     * @prop {Boolean} gpuAcceleration=true
2189
     * If true, it uses the CSS 3d transformation to position the popper.
2190
     * Otherwise, it will use the `top` and `left` properties.
2191
     */
2192
    gpuAcceleration: undefined
2193
  }
2194
};
2195
2196
/**
2197
 * The `dataObject` is an object containing all the informations used by Popper.js
2198
 * this object get passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
2199
 * @name dataObject
2200
 * @property {Object} data.instance The Popper.js instance
2201
 * @property {String} data.placement Placement applied to popper
2202
 * @property {String} data.originalPlacement Placement originally defined on init
2203
 * @property {Boolean} data.flipped True if popper has been flipped by flip modifier
2204
 * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper.
2205
 * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
2206
 * @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`)
2207
 * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow, it expects the JavaScript nomenclature (eg. `marginBottom`)
2208
 * @property {Object} data.boundaries Offsets of the popper boundaries
2209
 * @property {Object} data.offsets The measurements of popper, reference and arrow elements.
2210
 * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
2211
 * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
2212
 * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0
2213
 */
2214
2215
/**
2216
 * Default options provided to Popper.js constructor.<br />
2217
 * These can be overriden using the `options` argument of Popper.js.<br />
2218
 * To override an option, simply pass as 3rd argument an object with the same
2219
 * structure of this object, example:
2220
 * ```
2221
 * new Popper(ref, pop, {
2222
 *   modifiers: {
2223
 *     preventOverflow: { enabled: false }
2224
 *   }
2225
 * })
2226
 * ```
2227
 * @type {Object}
2228
 * @static
2229
 * @memberof Popper
2230
 */
2231
var Defaults = {
2232
  /**
2233
   * Popper's placement
2234
   * @prop {Popper.placements} placement='bottom'
2235
   */
2236
  placement: 'bottom',
2237
2238
  /**
2239
   * Whether events (resize, scroll) are initially enabled
2240
   * @prop {Boolean} eventsEnabled=true
2241
   */
2242
  eventsEnabled: true,
2243
2244
  /**
2245
   * Set to true if you want to automatically remove the popper when
2246
   * you call the `destroy` method.
2247
   * @prop {Boolean} removeOnDestroy=false
2248
   */
2249
  removeOnDestroy: false,
2250
2251
  /**
2252
   * Callback called when the popper is created.<br />
2253
   * By default, is set to no-op.<br />
2254
   * Access Popper.js instance with `data.instance`.
2255
   * @prop {onCreate}
2256
   */
2257
  onCreate: function onCreate() {},
2258
2259
  /**
2260
   * Callback called when the popper is updated, this callback is not called
2261
   * on the initialization/creation of the popper, but only on subsequent
2262
   * updates.<br />
2263
   * By default, is set to no-op.<br />
2264
   * Access Popper.js instance with `data.instance`.
2265
   * @prop {onUpdate}
2266
   */
2267
  onUpdate: function onUpdate() {},
2268
2269
  /**
2270
   * List of modifiers used to modify the offsets before they are applied to the popper.
2271
   * They provide most of the functionalities of Popper.js
2272
   * @prop {modifiers}
2273
   */
2274
  modifiers: modifiers
2275
};
2276
2277
/**
2278
 * @callback onCreate
2279
 * @param {dataObject} data
2280
 */
2281
2282
/**
2283
 * @callback onUpdate
2284
 * @param {dataObject} data
2285
 */
2286
2287
// Utils
2288
// Methods
2289
var Popper = function () {
2290
  /**
2291
   * Create a new Popper.js instance
2292
   * @class Popper
2293
   * @param {HTMLElement|referenceObject} reference - The reference element used to position the popper
2294
   * @param {HTMLElement} popper - The HTML element used as popper.
2295
   * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)
2296
   * @return {Object} instance - The generated Popper.js instance
2297
   */
2298
  function Popper(reference, popper) {
2299
    var _this = this;
2300
2301
    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2302
    classCallCheck(this, Popper);
2303
2304
    this.scheduleUpdate = function () {
2305
      return requestAnimationFrame(_this.update);
2306
    };
2307
2308
    // make update() debounced, so that it only runs at most once-per-tick
2309
    this.update = debounce(this.update.bind(this));
2310
2311
    // with {} we create a new object with the options inside it
2312
    this.options = _extends({}, Popper.Defaults, options);
2313
2314
    // init state
2315
    this.state = {
2316
      isDestroyed: false,
2317
      isCreated: false,
2318
      scrollParents: []
2319
    };
2320
2321
    // get reference and popper elements (allow jQuery wrappers)
2322
    this.reference = reference && reference.jquery ? reference[0] : reference;
2323
    this.popper = popper && popper.jquery ? popper[0] : popper;
2324
2325
    // Deep merge modifiers options
2326
    this.options.modifiers = {};
2327
    Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
2328
      _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
2329
    });
2330
2331
    // Refactoring modifiers' list (Object => Array)
2332
    this.modifiers = Object.keys(this.options.modifiers).map(function (name) {
2333
      return _extends({
2334
        name: name
2335
      }, _this.options.modifiers[name]);
2336
    })
2337
    // sort the modifiers by order
2338
    .sort(function (a, b) {
2339
      return a.order - b.order;
2340
    });
2341
2342
    // modifiers have the ability to execute arbitrary code when Popper.js get inited
2343
    // such code is executed in the same order of its modifier
2344
    // they could add new properties to their options configuration
2345
    // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
2346
    this.modifiers.forEach(function (modifierOptions) {
2347
      if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {
2348
        modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);
2349
      }
2350
    });
2351
2352
    // fire the first update to position the popper in the right place
2353
    this.update();
2354
2355
    var eventsEnabled = this.options.eventsEnabled;
2356
    if (eventsEnabled) {
2357
      // setup event listeners, they will take care of update the position in specific situations
2358
      this.enableEventListeners();
2359
    }
2360
2361
    this.state.eventsEnabled = eventsEnabled;
2362
  }
2363
2364
  // We can't use class properties because they don't get listed in the
2365
  // class prototype and break stuff like Sinon stubs
2366
2367
2368
  createClass(Popper, [{
2369
    key: 'update',
2370
    value: function update$$1() {
2371
      return update.call(this);
2372
    }
2373
  }, {
2374
    key: 'destroy',
2375
    value: function destroy$$1() {
2376
      return destroy.call(this);
2377
    }
2378
  }, {
2379
    key: 'enableEventListeners',
2380
    value: function enableEventListeners$$1() {
2381
      return enableEventListeners.call(this);
2382
    }
2383
  }, {
2384
    key: 'disableEventListeners',
2385
    value: function disableEventListeners$$1() {
2386
      return disableEventListeners.call(this);
2387
    }
2388
2389
    /**
2390
     * Schedule an update, it will run on the next UI update available
2391
     * @method scheduleUpdate
2392
     * @memberof Popper
2393
     */
2394
2395
2396
    /**
2397
     * Collection of utilities useful when writing custom modifiers.
2398
     * Starting from version 1.7, this method is available only if you
2399
     * include `popper-utils.js` before `popper.js`.
2400
     *
2401
     * **DEPRECATION**: This way to access PopperUtils is deprecated
2402
     * and will be removed in v2! Use the PopperUtils module directly instead.
2403
     * Due to the high instability of the methods contained in Utils, we can't
2404
     * guarantee them to follow semver. Use them at your own risk!
2405
     * @static
2406
     * @private
2407
     * @type {Object}
2408
     * @deprecated since version 1.8
2409
     * @member Utils
2410
     * @memberof Popper
2411
     */
2412
2413
  }]);
2414
  return Popper;
2415
}();
2416
2417
/**
2418
 * The `referenceObject` is an object that provides an interface compatible with Popper.js
2419
 * and lets you use it as replacement of a real DOM node.<br />
2420
 * You can use this method to position a popper relatively to a set of coordinates
2421
 * in case you don't have a DOM node to use as reference.
2422
 *
2423
 * ```
2424
 * new Popper(referenceObject, popperNode);
2425
 * ```
2426
 *
2427
 * NB: This feature isn't supported in Internet Explorer 10
2428
 * @name referenceObject
2429
 * @property {Function} data.getBoundingClientRect
2430
 * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.
2431
 * @property {number} data.clientWidth
2432
 * An ES6 getter that will return the width of the virtual reference element.
2433
 * @property {number} data.clientHeight
2434
 * An ES6 getter that will return the height of the virtual reference element.
2435
 */
2436
2437
2438
Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;
2439
Popper.placements = placements;
2440
Popper.Defaults = Defaults;
2441
2442
return Popper;
2443
2444
})));
2445
//# sourceMappingURL=popper.js.map
2446